package com.login.framework.core.xmlcommands;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.login.framework.core.BaseLoginCommand;
import com.login.framework.core.LoginActionsIDs;
import com.login.framework.model.User;

/**
 * Es la implementación por defecto del Command de login.
 * 
 * @author inyaky
 * 
 */
public class LoginCommand extends BaseLoginCommand {

	private static final String XML_RESULTSET = "xml_resultset";
	private static String LOGIN_XMLFILE_PATH = "users.xml";
	private static final String XPATH_EXPRESSION = "//user[@username='%s' and @password='%s']";

	protected User user = null;

	@Override
	public int getID() {
		return LoginActionsIDs.LOGIN;
	}

	/**
	 * La ruta al repositorio xml de usuarios.
	 * 
	 * @return
	 */
	private String getXMLFilePath() {
		return LOGIN_XMLFILE_PATH;
	}

	@Override
	protected Map<String, Object> job() {

		HashMap<String, Object> resultSet = new HashMap<String, Object>();

		DocumentBuilderFactory domFactory = DocumentBuilderFactory
				.newInstance();
		domFactory.setNamespaceAware(true);
		DocumentBuilder builder;

		try {
			builder = domFactory.newDocumentBuilder();

			Document doc = builder.parse(getXMLFilePath());

			resultSet.put(XML_RESULTSET, doc);
			resultSet.put(RESULT_CODE, OK);

		} catch (SAXException e) {
			e.printStackTrace();
			resultSet.put(RESULT_CODE, ERROR);
			resultSet.put(ERROR_MSG, e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			resultSet.put(ERROR_MSG, e.getMessage());
			resultSet.put(RESULT_CODE, ERROR);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
			resultSet.put(ERROR_MSG, e.getMessage());
			resultSet.put(RESULT_CODE, ERROR);
		}

		return resultSet;
	}

	@Override
	protected Map<String, Object> processLoginResult(
			Map<String, Object> resultSet) {

		Document doc = (Document) resultSet.get(XML_RESULTSET);

		XPath xpath = XPathFactory.newInstance().newXPath();

		try {
			XPathExpression expr = xpath.compile(String.format(
					XPATH_EXPRESSION, username, password));

			NodeList result = (NodeList) expr.evaluate(doc,
					XPathConstants.NODESET);

			if (result != null && result.getLength() > 0) {
				user = new User();
				user.setPassword(password);
				user.setUsername(username);
				resultSet.put(RESULT_CODE, OK);
			} else {
				resultSet.put(RESULT_CODE, ERROR);
				resultSet.put(ERROR_MSG, "Invalid Username or Password");
			}

		} catch (XPathExpressionException e) {
			e.printStackTrace();
			resultSet.put(ERROR_MSG, e.getMessage());
			resultSet.put(RESULT_CODE, ERROR);
		}

		return resultSet;
	}

	@Override
	public User getLoggedUser() {
		return user;
	}
}
